#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
单文件 Flask 演示（pysnmp 版）
1. 只使用不可伪造的 request.remote_addr
2. 5 秒内存缓存
3. 纯 pysnmp 实现 IP → 索引 → MAC
依赖：pip install flask pysnmp
"""

from flask import Flask, request,render_template, jsonify
from pysnmp.hlapi import *
import time,re

# ========== 配置 ==========
SWITCH_IP = "192.168.1.1"      # SNMP 设备
COMMUNITY = "public"            # 只读团体字
CACHE_TTL = 5                   # 秒
PORT      = 5000
LOG_FILE  = "log.txt"           # 日志文件
# ==========================



# ---------- 日志函数 ----------
def log(msg: str):
    """带时间戳写入 log.txt"""
    with open(LOG_FILE, "a", encoding="utf-8") as f:
        f.write(f"{time.strftime('%Y-%m-%d %H:%M:%S')} {msg}\n")

# ---------- pysnmp 工具（带耗时日志） ----------
def snmpget(oid: str) -> str:
    """
    拼接ODI查询；发送get请求
    snmpget -v 2c -c
    """
    t0 = time.time()
    errInd, errStat, _, varBinds = next(
        getCmd(SnmpEngine(),
              CommunityData(COMMUNITY, mpModel=1),
              UdpTransportTarget((SWITCH_IP, 161), timeout=3, retries=2),
              ContextData(),
              ObjectType(ObjectIdentity(oid))))
    if errInd or errStat:
        log(f"[SNMP] 进入if errInd or errStat: OID={oid} snmp地址错误或者{SWITCH_IP}不可达,检查网络后重试")
        print("snmp网络不可达或者读团体字错误")
        raise RuntimeError("snmp地址错误或者{SWITCH_IP}不可达")
    for v in varBinds:
        print('详情:', v[0].prettyPrint(), '=', v[1].prettyPrint())
        log(f"[SNMP] 详情:', {v[0].prettyPrint()}, '=', {v[1].prettyPrint()}")
    raw = str(varBinds[0][1]).strip()
    print(varBinds[0][1])
    log(f"[SNMP] OID={oid} 值为raw = {raw} 耗时={time.time() - t0:.3f}s 结果={raw[:20]}...")
    return raw
def snmpwalk(oid: str) -> str:
    errorInd, errorSt, errorIdx, varBinds = next(
        getCmd(SnmpEngine(),
               CommunityData(COMMUNITY),
               UdpTransportTarget((SWITCH_IP, 161), timeout=2, retries=0),
               ContextData(),
               ObjectType(ObjectIdentity(oid)))
    )
    if errorInd or errorSt:
        return str(errorInd or errorSt)
    oid, val = varBinds[0]
    return str(varBinds[0])


def get_user_index(ip: str) -> str:
    oid = f"1.3.6.1.4.1.2011.5.2.1.27.1.2.{ip}.8.95.112.117.98.108.105.99.95"
    # oid = f"1.3.6.1.4.1.2011.5.2.1.27.1.2.172.19.154.68.8.95.112.117.98.108.105.99.95"
    log(f"[FLASK] 索引查询 OID={oid} ")
    return snmpget(oid)
def get_mac_by_index(index: str) -> str:
    oid = f"1.3.6.1.4.1.2011.5.2.1.15.1.17.{index}"
    log(f"[FLASK] MAC查询OID: {oid}")
    raw = snmpwalk(oid).strip()
    print(raw)
    log(f"[FLASK] 原始MAC字符串: {raw!r}")
    raw = re.search(r'= 0x([0-9a-fA-F]+)', raw)
    if raw:
        hex_value = raw.group(1).upper()
        # 格式化为 XXXX-XXXX-XXXX
        formatted = '-'.join([hex_value[i:i + 4] for i in range(0, len(hex_value), 4)])
        print("格式化后的值是:", formatted)
        return formatted
    else:
        print("未匹配到十六进制值")
        return None

# ---------- 业务逻辑 ----------
# @cache_ttl(CACHE_TTL)
def query_ip_to_mac(ip: str) -> str:
    idx = get_user_index(ip)
    if idx:
        mac = get_mac_by_index(idx)
        return mac
    else:
        print("索引查询失败")




# ---------- Flask ----------
app = Flask(__name__)


# ----------- 路由 ----------- #
@app.route("/")
def index():
    ip = request.remote_addr
    log(f"[FLASK] 客户端 IP: {ip}")
    return render_template("index.html", ip=ip)

# @app.route("/api/mac")
# def api_mac():
#     #测试时开启，可以通过API方式请求
#     # ip = request.args.get("ip")
#     # ① 强制用连接层真实 IP，无视参数
#     ip = request.remote_addr
#     if not ip:
#         return jsonify(mac=None)
#     try:
#         mac = query_ip_to_mac(ip)
#     except RuntimeError:
#         return jsonify(mac=None)
#     # return jsonify(mac=mac)
#     return jsonify(
#         mac=mac,  # 真实 MAC 或 null
#         raw= mac or "检查当前WIFI是否为wifi名称"
#     )
@app.route("/api/mac")
def api_mac():
    ip = request.remote_addr
    if not ip:
        return jsonify(mac=None, raw="无法获取客户端 IP")
    try:
        mac = query_ip_to_mac(ip)
    except RuntimeError:
        mac = None
    return jsonify(mac=mac, raw=mac if mac is not None else "检查当前WIFI是否为{你的wifi名称}")

if __name__ == "__main__":
    log(f"=== 监听 0.0.0.0:{PORT} ===")
    app.run(host="0.0.0.0", port=PORT)